#ifndef _LINUX_CONFIG_H
#define _LINUX_CONFIG_H

#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <libgen.h>
#include <errno.h>
#include <stdlib.h>

#include <pthread.h>
#include <sched.h>
#include <sys/syscall.h>
#include <string.h>

#define FENG_TEST_DEBUG
// #define FENG_TEST_CPU_SET

#define SOCKET_PATH "/tmp/toCore"
#define SOCKET_BYTE_CNT 49

// #define SOCKET_SNED_OVERTIME_DEBUG
#define SOCKET_REC_OVERTIME_DEBUG



//back-ground:white front:green
#define TEST_START printf("\033[47;32m<<--[%s,%s,%d] start-->>\033[0m\r\n",__FILE__,__FUNCTION__,__LINE__)
#define TEST_END   printf("\033[47;32m<<--[%s,%s,%d]  end -->>\033[0m\r\n",__FILE__,__FUNCTION__,__LINE__)
//#define TEST_START
//#define TEST_END  
//#define TEST_START printf("<<-----------%-10s start----------->>\n",__FUNCTION__)
//#define TEST_END   printf("<<-----------%-10s   end----------->>\n",__FUNCTION__)

#ifdef FENG_TEST_DEBUG
    //kColorWhite  ---> info
    #define LOG_INFO(...)  (gettimeofday(&timeShow, NULL),printf("\033[0m[%ld.%06ld %s %s %d]",timeShow.tv_sec,timeShow.tv_usec,basename(__FILE__),__FUNCTION__,__LINE__),printf(__VA_ARGS__),printf("\r\n"))
    //kColorGreen  ---> normal
    #define LOG_DEBUG(...) (gettimeofday(&timeShow, NULL),printf("\033[32m[%ld.%06ld %s %s %d]",timeShow.tv_sec,timeShow.tv_usec,basename(__FILE__),__FUNCTION__,__LINE__),printf(__VA_ARGS__),printf("\033[0m\r\n"))
    //kColorYellow ---> warrning
    #define LOG_WARN(...)  (gettimeofday(&timeShow, NULL),printf("\033[33m[%ld.%06ld %s %s %d]",timeShow.tv_sec,timeShow.tv_usec,basename(__FILE__),__FUNCTION__,__LINE__),printf(__VA_ARGS__),printf("\033[0m\r\n"))
    //kColorRed    ---> error
    #define LOG_ERROR(...) (gettimeofday(&timeShow, NULL),printf("\033[31m[%ld.%06ld %s %s %d]",timeShow.tv_sec,timeShow.tv_usec,basename(__FILE__),__FUNCTION__,__LINE__),printf(__VA_ARGS__),printf("\033[0m\r\n"))
#else
    #define LOG_INFO(...)
    #define LOG_DEBUG(...)
    #define LOG_WARN(...)
    #define LOG_ERROR(...)
#endif

#ifdef FENG_TEST_CPU_SET
#define CPU_BINDING(cpu) \
    cpu_set_t mask;\
    CPU_ZERO(&mask);\
    CPU_SET(cpu, &mask)
#else
#define CPU_BINDING(cpu)
#endif

extern struct timeval timeShow;

static inline int thread_set_affinity(const char *thread_name, bool cpu0, bool cpu1, bool cpu2, bool cpu3)
{
	cpu_set_t mask;
	CPU_ZERO(&mask);

	if(cpu0)
		CPU_SET(0, &mask);

	if(cpu1)
		CPU_SET(1, &mask);

	if(cpu2)
		CPU_SET(2, &mask);

//	if(cpu3)
//		CPU_SET(3, &mask);

	if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
	{
		LOG_ERROR("Set CPU affinity failue, ERROR:%s\n", strerror(errno));
		return -1;
	}

	LOG_INFO("This thread (%s) %lu %d run at cpu (%d,%d,%d,%d).", thread_name, pthread_self(), syscall(__NR_gettid), \
	cpu0, cpu1, cpu2, cpu3);

	return 0;
}

static inline void thread_set_priority(const char *thread_name, int pol, int pri)
{
	LOG_INFO("This thread (%s) %lu %d", thread_name, pthread_self(), syscall(__NR_gettid));

	int policy;
	struct sched_param param;

	pthread_getschedparam(pthread_self(), &policy, &param);
	LOG_INFO("%s: before set: pol: %d, pri: %d!", thread_name, policy, param.sched_priority);

	policy = pol;
	param.sched_priority = pri;
	pthread_setschedparam(pthread_self(), policy, &param);

	pthread_getschedparam(pthread_self(), &policy, &param);
	LOG_INFO("%s: after  set: pol: %d, pri: %d!", thread_name, policy, param.sched_priority);

	// set thread affinity
	if( (strcmp(thread_name, "Server_Receive") == 0) || (strcmp(thread_name, "Server_Send") == 0) ||
		(strcmp(thread_name, "Client_Receive") == 0) || (strcmp(thread_name, "Client_Send") == 0) )
	{
		thread_set_affinity(thread_name, true, false, false, false);
	}
	else
	{
		thread_set_affinity(thread_name, false, true, true, true);
	}
}

#define SET_THREAD_SCHEDULE thread_set_priority(__FUNCTION__, SCHED_RR, 30)
// #define SET_THREAD_SCHEDULE

int64_t tUTCMSec();
int64_t tUTCUSec();
void DateDebug(char *str, uint8_t *buf, uint8_t len);

#endif
